#define _POSIX_SOURCE
#define _BSD_SOURCE

#include "dominion.h"
#include "dominion_helpers.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <math.h>
#include <errno.h>
#include <signal.h>
#include <unistd.h>
#include "rngs.h"
#include <getopt.h>

#ifndef TEST_CASES
#define TEST_CASES 10000
#endif

#ifndef RAND_NUM
#define RAND_NUM 100
#endif

#ifndef SUPP
#define SUPP 10
#endif

int createGameState(struct gameState *state, int card, int *handPos, int *choice1)
{
	int i, j;

	// Generate 2-4 players
	state->numPlayers = floor(Random() * (MAX_PLAYERS - 1)) + 2;
	state->whoseTurn = floor(Random() * state->numPlayers);

	state->numActions = floor(Random() * RAND_NUM);
	state->numBuys = floor(Random() * RAND_NUM);
	state->coins = floor(Random() * RAND_NUM);
	state->playedCardCount = floor(Random() * RAND_NUM);

	for (i = 0; i < state->numPlayers; i++) {
		state->handCount[i] = floor(Random() * RAND_NUM);
		state->deckCount[i] = floor(Random() * (RAND_NUM - 4)) + 5;
		state->discardCount[i] = floor(Random() * RAND_NUM);

		for (j = 0; j < state->handCount[i]; j++) {
			state->hand[i][j] = floor(Random() * (treasure_map + 1));
		}

		for (j = 0; j < state->deckCount[i]; j++) {
			state->deck[i][j] = floor(Random() * (treasure_map + 1));
		}

		for (j = 0; j < state->discardCount[i]; j++) {
			state->discard[i][j] = floor(Random() * (treasure_map + 1));
		}
	}

	// Make sure current player has the card to test
	if (state->handCount[state->whoseTurn] <= 0) {
		state->hand[state->whoseTurn][1] = card;
		state->hand[state->whoseTurn][0] = floor(Random() * (treasure_map + 1));
		state->handCount[state->whoseTurn] += 2;
		*handPos = 1;
		*choice1 = 0;
	} else if (state->handCount[state->whoseTurn] == 1) {
		state->hand[state->whoseTurn][0] = card;
		state->hand[state->whoseTurn][1] = floor(Random() * (treasure_map + 1));
		state->handCount[state->whoseTurn] += 1;
		*handPos = 0;
		*choice1 = 1;
	} else {
		*handPos = floor(Random() * state->handCount[state->whoseTurn]);
		state->hand[state->whoseTurn][*handPos] = card;

		//Choices are from the player's hand
		*choice1 = floor(Random() * state->handCount[state->whoseTurn]);
		while (*choice1 == *handPos) {
			*choice1 = floor(Random() * state->handCount[state->whoseTurn]);
		}
	}
	
	return 0;
}

int test_cardsalvager(struct gameState *state, int handPos, int choice1)
{
	int i;
	struct gameState pre;

	memcpy(&pre, state, sizeof(struct gameState));

	cardEffect(salvager, choice1, -1, -1, state, handPos, NULL);

	// SET UP EXPECTED CONDITIONS HERE
	pre.numBuys += 1;
	pre.coins += getCost(pre.hand[pre.whoseTurn][choice1]);
	pre.hand[pre.whoseTurn][choice1] = pre.hand[pre.whoseTurn][pre.handCount[pre.whoseTurn] - 1];
	pre.hand[pre.whoseTurn][pre.handCount[pre.whoseTurn] - 1] = -1;
	pre.handCount[pre.whoseTurn] -= 1;

	// Find and toss the played card
	for (i = 0; i < pre.handCount[pre.whoseTurn]; i++) {
		if (pre.hand[pre.whoseTurn][i] == salvager) {
			pre.playedCards[pre.playedCardCount] = salvager;
			pre.playedCardCount += 1;
			pre.hand[pre.whoseTurn][i] = pre.hand[pre.whoseTurn][pre.handCount[pre.whoseTurn] -1];
			pre.hand[pre.whoseTurn][pre.handCount[pre.whoseTurn] - 1] = -1;
			pre.handCount[pre.whoseTurn] -= 1;
			break;
		}
	}

	if (pre.numBuys != state->numBuys) {
		printf("\t# BUYS DO NOT MATCH!!!\n");
	}

	if (pre.handCount[pre.whoseTurn] != state->handCount[state->whoseTurn]) {
		printf("\t# HANDCOUNT DOES NOT MATCH\n");
	} else {
		for (i = 0; i < state->handCount[state->whoseTurn]; i++) {
			if (pre.hand[pre.whoseTurn][i] != state->hand[state->whoseTurn][i]) {
				printf("\t# HAND CONTENT DOES NOT MATCH\n");
			}
		}
	}

	if (pre.playedCardCount	!= state->playedCardCount) {
		printf("\t# PLAYEDCARDCOUNT DOES NOT MATCH\n");
	} else {
		if (state->playedCards[state->playedCardCount - 1] != salvager) {
			printf("\t# IMPROPERLY UPDATED PLAYEDCARDS\n");
		}
	}


	if (memcmp(&pre, state, sizeof(struct gameState)) != 0) {
		return -1;
	}

	return 0;
}

int main(int argc, char **argv)
{
	int i, result, handPos, choice1, counter = 0;
	struct gameState state;

	for (i = 0; i < TEST_CASES; i++) {

		// Reset variables
		handPos = 0;
		choice1 = 0;
		
		createGameState(&state, salvager, &handPos, &choice1);
		result = test_cardsalvager(&state, handPos, choice1);
		if (result == 0) {
			printf("TEST CASE #%d = PASS\n", i + 1);
			counter += 1;
		} else {
			printf("TEST CASE #%d = FAIL <------\n", i + 1);
		}
	}

	printf("PASSED CASES: %d out of %d\n", counter, TEST_CASES);
	return 0;
}